package netty.builder;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

public class NettyServerBuilder extends NettyBuilderBase<NettyServerBuilder> {
    private static final Logger LOG = LoggerFactory.getLogger(NettyServerBuilder.class);
    private String name = ""; // 服务名称，用于日志记录
    private EventLoopGroup parentGroup;
    private EventLoopGroup childGroup;
    private Map<ChannelOption, Object> childOptions = new HashMap<>();

    public NettyServerBuilder() {
        // 设定默认值，后续相同设置参数会覆盖此值
        options.put(ChannelOption.SO_BACKLOG, 1000);
        childOptions.put(ChannelOption.SO_KEEPALIVE, true);
    }

    /**
     * 创建一个未绑定到端口的ServerBootstrap
     * @return
     */
    @SuppressWarnings("unchecked")
    public ServerBootstrap build() {
        Assert.isTrue(channelInitializer != null || pipelineHandlers.size() > 0, "请指定childChannelInitializer或pipelineHandlers");
        if (channelClass == null) {
            channelClass = OS.getDefaultServerChannelClass();
        }
        if (parentGroup == null) {
            parentGroup = OS.defaultLoopGroup();
        }
        if (childGroup == null) {
            childGroup = OS.defaultLoopGroup();
        }

        ServerBootstrap bs = new ServerBootstrap();
        bs.group(parentGroup, childGroup).channel((Class<ServerChannel>) channelClass)
                .childHandler(channelInitializer != null ? channelInitializer : defaultChildHandler);
        options.forEach(bs::option);
        childOptions.forEach(bs::childOption);
        return bs;
    }

    /**
     * 创建并启动Netty服务，关闭服务请使用方法 ChannelFuture.channel().close()
     * @param port
     * @return
     */
    public ChannelFuture buildAndBind(int port) {
        ChannelFuture f = build().bind(port);
        try {
            f.sync();
            LOG.debug("Netty服务已启动：" + name);
        } catch (InterruptedException e) {
            throw new RuntimeException("启动Netty服务失败：" + name, e);
        }
        return f;
    }

    /**
     * 创建并异步启动Netty服务，关闭服务请使用方法 ChannelFuture.channel().close()
     * @param port
     * @return
     */
    public ChannelFuture buildAndBindAsync(int port) {
        ChannelFuture f = build().bind(port);
        f.addListener(future -> {
            if (future.isSuccess()) {
                LOG.debug("Netty服务已启动：" + name);
            } else {
                throw new RuntimeException("Netty服务启动失败：" + name);
            }
        });
        return f;
    }

    public NettyServerBuilder name(String name) {
        this.name = name;
        return this;
    }

    /**
     * 可选配置。指定EventLoopGroup时，注意channelClass与EventLoopGroup匹配。默认在Linux系统下使用EpollEventLoopGroup和EpollServerSocketChannel，
     * 其它系统下使用NioEventLoopGroup和NioServerSocketChannel
     * @param group 指定的LoopGroup在channel关闭时需要自行清理
     * @return
     */
    public NettyServerBuilder parentGroup(EventLoopGroup group) {
        Assert.notNull(group, "EventGroup不能为null");
        this.parentGroup = group;
        return this;
    }

    /**
     * 可选配置。指定EventLoopGroup时，注意channelClass与EventLoopGroup匹配。
     * @see #parentGroup(EventLoopGroup group)
     * @param group 指定的LoopGroup在channel关闭时需要自行清理
     * @return
     */
    public NettyServerBuilder childGroup(EventLoopGroup group) {
        Assert.notNull(group, "EventGroup不能为null");
        this.childGroup = group;
        return this;
    }

    /**
     * 设置子Channel参数
     * @param option
     * @param value
     * @param <T>
     * @return
     */
    public <T> NettyServerBuilder childOption(ChannelOption<T> option, T value) {
        childOptions.put(option, value);
        return this;
    }
}
